#include<bits/stdc++.h> 
using namespace std;
//	警察查找一个犯罪团伙头领的方法就是查他们的通话记录。如果有A和B之间的通信，我们就说A和
//	B是有关联的。关联权重定义为A和B之间所有的通话时长之和。一个犯罪团伙指的是2个及以上的
//	相互关联的人且相互间的关联权重大于某个阈值K。在每个团伙中，权重最大的人就是所谓的头目
//	。现在给定一系列的通话记录，找到其中的团伙以及头目
//1.每个输入包含一个测试用例，对于每个测试用例，第一行是两个不大于1000的正整数N和K，分别
//	表示通话记录总数和权重阈值。
//2.接下来的N行，每一行都是 姓名1  姓名2   时长 的结构。其中姓名1和姓名2是通话双方的名字
//	时长是这通电话的时长。一个名字由3个大写字母组成，一个通话时长是不大于1000的正整数
//3.对于每一个测试用例，首先在一行输出团伙的数量，然后对于每一个团伙，输出一行团伙头目的
//	名称以及成员数量
//4.题目保证每一个团队的头领都是唯一的。团伙之间的排序按照首领姓名字典序排列
//5.连通分量，DFS
//这题跟前面求连通分量的题差不多，加上过年事儿比较多，这题也照搬一下别的大佬的代码了 
int N,K;//边数和阈值
bool visited[2000];//访问标记数组
int G[2000][2000];// 邻接矩阵，其值为边权
int node_weight[2000];// 点权
unordered_map<int,string> indexToName;// 存储编号到姓名的映射
unordered_map<string,int> nameToIndex;// 存储姓名到编号的映射
map<string,int> result;// 每一个gang的head和人数集合
int numPerson = 0;//总人数

void DFS(int start,int &number,int &total_time,int &head){
    visited[start] = true;// 访问该节点
    ++number;// 当前连通分量节点数目加一
    if(node_weight[head]<node_weight[start]){
        // 更新head
        head = start;
    }
    // 遍历每一个领接点
    for(int i=0;i<numPerson;++i){
        if(G[start][i]!=0){
            // i是start的领接点
            total_time += G[start][i];// 先累计总时长,为了防止出现环的时候少访问一条边
            // start->i的边只能访问一遍,得置为0，防止重复计算影响结果
            G[start][i] = G[i][start] = 0;
            if(!visited[i]){
                DFS(i,number,total_time,head);
            }
        }
    }
}

void DFSTraverse(){
    for (int i = 0; i < numPerson; ++i) {
        if(!visited[i]){
            int number = 0;// 每一个gang的人数
            int total_time = 0;// 每一个gang的总通话时长
            int head = i;// 每一个gang的head,初始得是当前访问连通块中的点，不能是0
            DFS(i,number,total_time,head);
            if(number>2&&total_time>K){
                // 当前连通分量是一个gang
                result[indexToName[head]] = number;
            }
        }
    }
    printf("%lu\n",result.size());
    map<string,int>::iterator it;
    for(it=result.begin();it!=result.end();++it){
        printf("%s %d\n",it->first.c_str(),it->second);
    }
}

int main()
{
    scanf("%d %d",&N,&K);
    string a,b;
    int time,index_a,index_b;
    for (int i = 0; i < N; ++i) {
        cin>>a>>b>>time;
        if(nameToIndex.find(a)==nameToIndex.end()){
            // 第一次出现,赋予编号
            index_a = numPerson++;
            nameToIndex[a] = index_a;
            indexToName[index_a] = a;
        } else {
            // 不是第一次出现，取出编号
            index_a = nameToIndex[a];
        }
        if(nameToIndex.find(b)==nameToIndex.end()){
            // 第一次出现,赋予编号
            index_b = numPerson++;
            nameToIndex[b] = index_b;
            indexToName[index_b] = b;
        } else {
            // 不是第一次出现，取出编号
            index_b = nameToIndex[b];
        }
        // 边权
        G[index_a][index_b] += time;
        G[index_b][index_a] += time;
        // 点权
        node_weight[index_a] += time;
        node_weight[index_b] += time;
    }
    DFSTraverse();
    return 0;
}